home *** CD-ROM | disk | FTP | other *** search
- /*
- * PPPIPCP.C -- negotiate IP parameters
- *
- * This implementation of PPP is declared to be in the public domain.
- *
- * Jan 91 Bill_Simpson@um.cc.umich.edu
- * Computer Systems Consulting Services
- *
- * Acknowledgements and correction history may be found in PPP.C
- */
-
- #include "global.h"
- #ifdef PPP
- #include "mbuf.h"
- #include "iface.h"
- #include "slhc.h"
- #include "ppp.h"
- #include "pppfsm.h"
- #include "pppipcp.h"
- #include "cmdparse.h"
- #include "files.h"
- #include "trace.h"
-
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: pppipcp.c,v 1.12 1996/12/23 20:37:36 root Exp root $";
- #endif
-
- /* These defaults are defined in the PPP RFCs, and must not be changed */
- static struct ipcp_value_s ipcp_default =
- {
- FALSE, /* no need to negotiate defaults */
-
- 0L, /* no source address */
- 0L, /* no destination address */
-
- 0, /* no compression protocol */
- 0, /* no slots */
- 0 /* no slot compression */
- };
-
- /* for test purposes, accept anything we understand */
- static int16 ipcp_negotiate = IPCP_N_ADDRESSES | IPCP_N_COMPRESS | IPCP_N_ADDRESS;
-
- static byte_t option_length[] =
- {
- 0, /* unused */
- 10, /* ip addresses */
- 6, /* compression */
- 6 /* ip address */
- };
-
-
- static int doipcp_local (int argc, char *argv[], void *p);
- static int doipcp_open (int argc, char *argv[], void *p);
- static int doipcp_pool (int argc, char *argv[], void *p);
- static int doipcp_remote (int argc, char *argv[], void *p);
-
- static int doipcp_address (int argc, char *argv[], void *p);
- static int doipcp_compress (int argc, char *argv[], void *p);
- static int doipcp_default (int argc, char *argv[], void *p);
-
- static void ipcp_option (struct mbuf ** bpp, struct ipcp_value_s * value_p,
- byte_t o_type, byte_t o_length, struct mbuf ** copy_bpp);
- static void ipcp_makeoptions (struct mbuf ** bpp, struct ipcp_value_s * value_p, int16 negotiating);
- static struct mbuf *ipcp_makereq (struct fsm_s * fsm_p);
-
- static int ipcp_check (struct mbuf ** bpp, struct ipcp_s * ipcp_p,
- struct ipcp_side_s * side_p, struct option_hdr * option_p, int request);
-
- static int ipcp_request (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
- static int ipcp_ack (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
- static int ipcp_nak (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
- static int ipcp_reject (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
-
- static void ipcp_reset (struct fsm_s * fsm_p);
-
- static uint32 ipcp_addr_idle (uint32 addr);
- static uint32 ipcp_lookuppeer (char *peerid);
- static uint32 ipcp_poolnext (struct ipcp_s * ipcp_p);
-
- static void ipcp_starting (struct fsm_s * fsm_p);
- static void ipcp_stopping (struct fsm_s * fsm_p);
-
- static void ipcp_closing (struct fsm_s * fsm_p);
- static void ipcp_opening (struct fsm_s * fsm_p);
-
- static void ipcp_free (struct fsm_s * fsm_p);
-
-
- static struct fsm_constant_s ipcp_constants =
- {
- "IPcp",
- PPP_IPCP_PROTOCOL,
- 0x00FE, /* codes 1-7 recognized */
-
- IPcp,
- IPCP_REQ_TRY,
- IPCP_NAK_TRY,
- IPCP_TERM_TRY,
- IPCP_TIMEOUT * 1000L,
-
- ipcp_free,
-
- ipcp_reset,
- ipcp_starting,
- ipcp_opening,
- ipcp_closing,
- ipcp_stopping,
-
- ipcp_makereq,
- ipcp_request,
- ipcp_ack,
- ipcp_nak,
- ipcp_reject,
- };
-
-
- /************************************************************************/
-
- /* "ppp <iface> ipcp" subcommands */
- static struct cmds IPcpcmds[] =
- {
- { "close", doppp_close, 0, 0, NULLCHAR },
- { "listen", doppp_passive, 0, 0, NULLCHAR },
- { "local", doipcp_local, 0, 0, NULLCHAR },
- { "open", doipcp_open, 0, 0, NULLCHAR },
- { "pool", doipcp_pool, 0, 0, NULLCHAR },
- { "remote", doipcp_remote, 0, 0, NULLCHAR },
- { "timeout", doppp_timeout, 0, 0, NULLCHAR },
- { "try", doppp_try, 0, 0, NULLCHAR },
- { NULLCHAR, 0, 0, 0, NULLCHAR }
- };
-
-
- /* { "ppp <iface> ipcp {local | remote}" subcommands */
- static struct cmds IPcpside_cmds[] =
- {
- { "address", doipcp_address, 0, 0, NULLCHAR },
- { "compress", doipcp_compress, 0, 0, NULLCHAR },
- { "default", doipcp_default, 0, 0, NULLCHAR },
- { NULLCHAR, 0, 0, 0, NULLCHAR }
- };
-
-
-
- int
- doppp_ipcp (int argc, char *argv[], void *p)
- {
- register struct iface *ifp = p;
- register struct ppp_s *ppp_p = ifp->edv;
-
- return subcmd (IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
- }
-
-
-
- static int
- doipcp_local (int argc, char *argv[], void *p)
- {
- struct fsm_s *fsm_p = p;
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- return subcmd (IPcpside_cmds, argc, argv, &(ipcp_p->local));
- }
-
-
-
- static int
- doipcp_open (int argc, char *argv[], void *p)
- {
- struct fsm_s *fsm_p = p;
-
- (void) doppp_active (argc, argv, p);
-
- if (fsm_p->ppp_p->phase == pppREADY)
- fsm_start (fsm_p);
-
- return 0;
- }
-
-
-
- /* Set a pool of peer addresses for PPP interface */
- static int
- doipcp_pool (int argc, char *argv[], void *p)
- {
- struct fsm_s *fsm_p = p;
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- uint32 pool_addr;
- int pool_cnt;
-
- if (argc < 2) {
- if (ipcp_p->peer_min == 0L)
- tputs ("None");
- else {
- tprintf ("%s thru ", inet_ntoa (ipcp_p->peer_min));
- tprintf ("%s\n", inet_ntoa (ipcp_p->peer_max));
- }
- return 0;
- }
- if ((pool_addr = resolve (argv[1])) == 0L)
- tprintf (Badhost, argv[1]);
-
- /* May specify a consecutive range of addresses; otherwise assume 1 */
- if (argc < 3)
- pool_cnt = 1;
- else
- pool_cnt = (int) strtol (argv[2], NULLCHARP, 0);
-
- if (pool_cnt <= 0) {
- tprintf ("Pool count %s (%d) must be > 0\n", argv[2], pool_cnt);
- return -1;
- }
- ipcp_p->peer_min = pool_addr;
- ipcp_p->peer_max = pool_addr + (unsigned long) pool_cnt - 1;
- return 0;
- }
-
-
-
- static int
- doipcp_remote (int argc, char *argv[], void *p)
- {
- struct fsm_s *fsm_p = p;
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- return subcmd (IPcpside_cmds, argc, argv, &(ipcp_p->remote));
- }
-
-
-
- /************************************************************************/
- /* Set addresses for PPP interface */
- static int
- doipcp_address (int argc, char *argv[], void *p)
- {
- struct ipcp_side_s *side_p = p;
- uint32 x32;
-
- if (argc < 2) {
- tprintf ("%s\n", inet_ntoa (side_p->want.address));
- return 0;
- } else if (stricmp (argv[1], "allow") == 0)
- return bit16cmd (&(side_p->will_negotiate), IPCP_N_ADDRESSES, "Allow Address", --argc, &argv[1]);
-
- if ((x32 = resolve (argv[1])) == 0L)
- tprintf (Badhost, argv[1]);
-
- side_p->want.address = x32;
- side_p->want.negotiate |= IPCP_N_ADDRESSES;
- return 0;
- }
-
-
-
- /* Set IP compression type for PPP interface */
- static int
- doipcp_compress (int argc, char *argv[], void *p)
- {
- struct ipcp_side_s *side_p = p;
-
- if (argc < 2) {
- if (side_p->want.negotiate & IPCP_N_COMPRESS) {
- switch (side_p->want.compression) {
- case PPP_COMPR_PROTOCOL:
- tprintf ("TCP header compression enabled; Slots = %d, slot compress = %x\n",
- side_p->want.slots, side_p->want.slot_compress);
- break;
- default:
- tprintf ("0x%04x\n", side_p->want.compression);
- break;
- }
- } else
- tputs ("None\n");
- } else if (stricmp (argv[1], "allow") == 0)
- return bit16cmd (&(side_p->will_negotiate), IPCP_N_COMPRESS,
- "Allow Compression", --argc, &argv[1]);
- else if (stricmp (argv[1], "tcp") == 0 || stricmp (argv[1], "vj") == 0) {
- side_p->want.compression = PPP_COMPR_PROTOCOL;
- if (argc >= 3) {
- side_p->want.slots = (int16) strtol (argv[2], NULLCHARP, 0);
- if (side_p->want.slots < 1 || side_p->want.slots > 255) {
- tputs ("slots must be in range 1 to 255");
- return 1;
- }
- } else
- side_p->want.slots = IPCP_SLOT_DEFAULT;
-
- if (argc >= 4)
- side_p->want.slot_compress = uchar (strtol (argv[3], NULLCHARP, 0));
- else
- side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
-
- side_p->want.negotiate |= IPCP_N_COMPRESS;
- } else if (stricmp (argv[1], "none") == 0)
- side_p->want.negotiate &= ~IPCP_N_COMPRESS;
- else {
- tputs ("allow tcp none\n");
- return 1;
- }
- return 0;
- }
-
-
-
- static int
- doipcp_default (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
- {
- struct ipcp_side_s *side_p = p;
-
- ASSIGN (side_p->want, ipcp_default);
- return 0;
- }
-
-
-
- /************************************************************************/
- /* E V E N T P R O C E S S I N G */
- /************************************************************************/
-
- static void
- ipcp_option (
- struct mbuf **bpp,
- struct ipcp_value_s *value_p,
- byte_t o_type,
- byte_t o_length,
- struct mbuf **copy_bpp
- ) {
- struct mbuf *bp;
- register unsigned char *cp;
- register int toss = o_length - OPTION_HDR_LEN;
-
- if ((bp = alloc_mbuf (o_length)) == NULLBUF)
- return;
-
- cp = bp->data;
- *cp++ = o_type;
- *cp++ = o_length;
-
- switch (o_type) {
- case IPCP_ADDRESSES:
- cp = put32 (cp, value_p->address);
- cp = put32 (cp, value_p->other);
- toss -= 8;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS) {
- trace_log (PPPiface, " making IP source address: %s",
- inet_ntoa (value_p->address));
- trace_log (PPPiface, " making IP destination address %s",
- inet_ntoa (value_p->other));
- }
- #endif
- break;
-
- case IPCP_COMPRESS:
- cp = put16 (cp, value_p->compression);
- toss -= 2;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, " making IP compression 0x%04x",
- value_p->compression);
- #endif
- if (value_p->compression == PPP_COMPR_PROTOCOL) {
- *cp++ = uchar (value_p->slots - 1);
- *cp++ = value_p->slot_compress;
- toss -= 2;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, " with IP compression slots %d, flag %x",
- value_p->slots, value_p->slot_compress);
- #endif
- }
- break;
-
- case IPCP_ADDRESS: /* Added By LAK */
- cp = put32(cp, value_p->address);
- toss -= 4;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log(PPPiface, " making IP source address: %s",
- inet_ntoa(value_p->address));
- #endif
- break;
-
- default:
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, " making unimplemented type %d", o_type);
- #endif
- break;
- }
-
- while (toss-- > 0)
- *cp++ = uchar (pullchar (copy_bpp));
-
- bp->cnt += o_length;
- append (bpp, bp);
- }
-
-
-
- /************************************************************************/
- /* Build a list of options */
- static void
- ipcp_makeoptions (struct mbuf **bpp, struct ipcp_value_s *value_p, int16 negotiating)
- {
- register int o_type;
-
- PPP_DEBUG_ROUTINES ("ipcp_makeoptions()");
-
- for (o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++) {
- if (negotiating & (1 << o_type))
- ipcp_option (bpp, value_p, uchar (o_type), option_length[o_type], NULLBUFP);
- }
- }
-
-
-
- /************************************************************************/
- /* Build a request to send to remote host */
- static struct mbuf *
- ipcp_makereq (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- struct mbuf *req_bp = NULLBUF;
-
- PPP_DEBUG_ROUTINES ("ipcp_makereq()");
-
- ipcp_makeoptions (&req_bp, &(ipcp_p->local.work), ipcp_p->local.work.negotiate);
- return (req_bp);
- }
-
-
-
- /************************************************************************/
- /* Check the options, updating the working values.
- * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
- */
- static int
- ipcp_check (
- struct mbuf **bpp,
- struct ipcp_s *ipcp_p,
- struct ipcp_side_s *side_p,
- struct option_hdr *option_p,
- int request
- ) {
- int toss = option_p->len - OPTION_HDR_LEN;
- int option_result = CONFIG_ACK; /* Assume good values */
- int test;
-
- switch (option_p->type) {
- case IPCP_ADDRESSES:
- side_p->work.address = pull32 (bpp);
- side_p->work.other = pull32 (bpp);
- toss -= 8;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS) {
- trace_log (PPPiface, " checking IP source address: %s",
- inet_ntoa (side_p->work.address));
- trace_log (PPPiface, " checking IP destination address %s",
- inet_ntoa (side_p->work.other));
- }
- #endif
- if (!request) {
- /* override any undesirable changes */
- if (ipcp_p->remote.want.address != 0L)
- ipcp_p->local.work.other = ipcp_p->remote.want.address;
-
- if (ipcp_p->local.want.address != 0L)
- ipcp_p->local.work.address = ipcp_p->local.want.address;
-
- break;
- }
- /* Ensure that addresses match */
- if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
- if (ipcp_p->remote.want.address == 0L)
- /* don't know address either */
- option_result = CONFIG_REJ;
-
- } else if (ipcp_p->remote.want.address == 0L)
- ipcp_p->local.work.other = ipcp_p->remote.work.address;
- else {
- ipcp_p->remote.work.address = ipcp_p->remote.want.address;
- option_result = CONFIG_NAK;
- }
-
- if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
- if (ipcp_p->local.want.address == 0L)
- /* don't know address either */
- option_result = CONFIG_REJ;
-
- } else if (ipcp_p->local.want.address == 0L)
- ipcp_p->local.work.address = ipcp_p->remote.work.other;
- else {
- option_result = CONFIG_NAK;
- ipcp_p->remote.work.other = ipcp_p->local.want.address;
- }
- break;
-
- case IPCP_COMPRESS:
- side_p->work.compression = pull16 (bpp);
- toss -= 2;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, " checking IP compression 0x%04x",
- side_p->work.compression);
- #endif
- /* Check if requested type is acceptable */
- switch (side_p->work.compression) {
- case PPP_COMPR_PROTOCOL:
- if ((test = pullchar (bpp)) == -1)
- return -1;
-
- if ((side_p->work.slots = (int16) (test + 1)) < IPCP_SLOT_LO) {
- side_p->work.slots = IPCP_SLOT_LO;
- option_result = CONFIG_NAK;
- } else if (side_p->work.slots > IPCP_SLOT_HI) {
- side_p->work.slots = IPCP_SLOT_HI;
- option_result = CONFIG_NAK;
- }
- if ((test = pullchar (bpp)) == -1)
- return -1;
-
- if ((side_p->work.slot_compress = uchar (test)) > 1) {
- side_p->work.slot_compress = 1;
- option_result = CONFIG_NAK;
- }
- toss -= 2;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, " with IP compression slots %d, flag %x",
- side_p->work.slots,
- side_p->work.slot_compress);
- #endif
- break;
-
- default:
- if (side_p->want.negotiate & IPCP_N_COMPRESS) {
- side_p->work.compression = side_p->want.compression;
- side_p->work.slots = side_p->want.slots;
- side_p->work.slot_compress = side_p->want.slot_compress;
- } else {
- side_p->work.compression = PPP_COMPR_PROTOCOL;
- side_p->work.slots = IPCP_SLOT_DEFAULT;
- side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
- }
- option_result = CONFIG_NAK;
- break;
- }
- break;
-
- case IPCP_ADDRESS: /* Added By LAK */
- side_p->work.address = pull32(bpp);
- toss -= 4;
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log(PPPiface, " checking IP source address: %s",
- inet_ntoa(side_p->work.address));
- #endif
- if ( !request ) {
- /* override any undesirable changes */
- if (ipcp_p->local.want.address != 0L)
- ipcp_p->local.work.address = ipcp_p->local.want.address;
- break;
- }
-
- if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
- if (ipcp_p->local.want.address == 0L)
- /* don't know address either */
- option_result = CONFIG_REJ;
- } else if (ipcp_p->local.want.address == 0L)
- ipcp_p->local.work.address = ipcp_p->remote.work.other;
- else {
- option_result = CONFIG_NAK;
- ipcp_p->remote.work.other = ipcp_p->local.want.address;
- }
- break;
-
- default:
- option_result = CONFIG_REJ;
- break;
- }
-
- if (option_p->type > IPCP_OPTION_LIMIT || !(side_p->will_negotiate & (1 << option_p->type)))
- option_result = CONFIG_REJ;
-
- if (toss < 0)
- return -1;
-
- if (!request && toss > 0) {
- /* toss extra bytes in option */
- while (toss-- > 0) {
- if (pullchar (bpp) == -1)
- return -1;
- }
- }
- return (option_result);
- }
-
-
-
- /************************************************************************/
- /* Check options requested by the remote host */
- static int
- ipcp_request (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- int32 signed_length = config->len;
- struct mbuf *reply_bp = NULLBUF; /* reply packet */
- int reply_result = CONFIG_ACK; /* reply to request */
- int16 desired; /* desired to negotiate */
- struct option_hdr option; /* option header storage */
- int option_result; /* option reply */
-
- PPP_DEBUG_ROUTINES ("ipcp_request()");
- ipcp_p->remote.work.negotiate = FALSE; /* clear flags */
-
- /* Process options requested by remote host */
- while (signed_length > 0 && ntohopt (&option, &data) != -1) {
- if ((signed_length -= option.len) < 0) {
- PPP_DEBUG_CHECKS ("IPCP REQ: bad header length");
- free_p (data);
- free_p (reply_bp);
- return -1;
- }
- if ((option_result = ipcp_check (&data, ipcp_p, &(ipcp_p->remote), &option, TRUE)) == -1) {
- PPP_DEBUG_CHECKS ("IPCP REQ: ran out of data");
- free_p (data);
- free_p (reply_bp);
- return -1;
- }
- #ifdef PPP_DEBUG_OPTIONS
- if (PPPtrace & PPP_DEBUG_OPTIONS)
- trace_log (PPPiface, "IPCP REQ: result %s, option %d, length %d",
- fsmCodes[option_result], option.type, option.len);
- #endif
- if (option_result < reply_result)
- continue;
- else if (option_result > reply_result) {
- /* Discard current list of replies */
- free_p (reply_bp);
- reply_bp = NULLBUF;
- reply_result = option_result;
- }
- /* remember that we processed option */
- if (option_result != CONFIG_REJ && option.type <= IPCP_OPTION_LIMIT)
- ipcp_p->remote.work.negotiate |= (1 << option.type);
-
- /* Add option response to the return list */
- ipcp_option (&reply_bp, &(ipcp_p->remote.work), option.type, option.len, &data);
- }
-
- /* Now check for any missing options which are desired */
- if (fsm_p->retry_nak > 0 && (desired = ipcp_p->remote.want.negotiate & ~ipcp_p->remote.work.negotiate) != 0) {
- switch (reply_result) {
- case CONFIG_ACK:
- free_p (reply_bp);
- reply_bp = NULLBUF;
- reply_result = CONFIG_NAK;
- /* fallthru */
- case CONFIG_NAK:
- ipcp_makeoptions (&reply_bp, &(ipcp_p->remote.want), desired);
- fsm_p->retry_nak--;
- break;
- case CONFIG_REJ:
- default:
- /* do nothing */
- break;
- }
- } else if (reply_result == CONFIG_NAK) {
- /* if too many NAKs, reject instead */
- if (fsm_p->retry_nak > 0)
- fsm_p->retry_nak--;
- else
- reply_result = CONFIG_REJ;
- }
- /* Send ACK/NAK/REJ to remote host */
- (void) fsm_send (fsm_p, uchar (reply_result), config->id, reply_bp);
- free_p (data);
- return (reply_result != CONFIG_ACK);
- }
-
-
-
- /************************************************************************/
- /* Process configuration ACK sent by remote host */
- static int
- ipcp_ack (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
- {
- struct mbuf *req_bp;
- int error = FALSE;
-
- PPP_DEBUG_ROUTINES ("ipcp_ack()");
-
- /* ID field must match last request we sent */
- if (config->id != fsm_p->lastid) {
- PPP_DEBUG_CHECKS ("IPCP ACK: wrong ID");
- free_p (data);
- return -1;
- }
- /* Get a copy of last request we sent */
- req_bp = ipcp_makereq (fsm_p);
-
- /* Overall buffer length should match */
- if (config->len != len_p (req_bp)) {
- PPP_DEBUG_CHECKS ("IPCP ACK: buffer length mismatch");
- error = TRUE;
- } else {
- register int req_char;
- register int ack_char;
-
- /* Each byte should match */
- while ((req_char = pullchar (&req_bp)) != -1) {
- if ((ack_char = pullchar (&data)) == -1 || ack_char != req_char) {
- PPP_DEBUG_CHECKS ("IPCP ACK: data mismatch");
- error = TRUE;
- break;
- }
- }
- }
- free_p (req_bp);
- free_p (data);
-
- if (error)
- return -1;
-
- PPP_DEBUG_CHECKS ("IPCP ACK: valid");
- return 0;
- }
-
-
-
- /************************************************************************/
- /* Process configuration NAK sent by remote host */
- static int
- ipcp_nak (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- struct ipcp_side_s *local_p = &(ipcp_p->local);
- int32 signed_length = config->len;
- struct option_hdr option;
- int last_option = 0;
- int result;
-
- PPP_DEBUG_ROUTINES ("ipcp_nak()");
-
- /* ID field must match last request we sent */
- if (config->id != fsm_p->lastid) {
- PPP_DEBUG_CHECKS ("IPCP NAK: wrong ID");
- free_p (data);
- return -1;
- }
- /* First, process in order. Then, process extra "important" options */
- while (signed_length > 0 && ntohopt (&option, &data) != -1) {
- if ((signed_length -= option.len) < 0) {
- PPP_DEBUG_CHECKS ("IPCP NAK: bad header length");
- free_p (data);
- return -1;
- }
- if (option.type > IPCP_OPTION_LIMIT)
- PPP_DEBUG_CHECKS ("IPCP NAK: option out of range");
- else if (option.type < last_option
- || !(local_p->work.negotiate & (1 << option.type))) {
- if (local_p->work.negotiate & (1 << option.type)) {
- PPP_DEBUG_CHECKS ("IPCP NAK: option out of order");
- free_p (data);
- return -1; /* was requested */
- }
- local_p->work.negotiate |= (1 << option.type);
- last_option = IPCP_OPTION_LIMIT + 1;
- } else
- last_option = option.type;
-
- if ((result = ipcp_check (&data, ipcp_p, local_p, &option, FALSE)) == -1) {
- PPP_DEBUG_CHECKS ("IPCP NAK: ran out of data");
- free_p (data);
- return -1;
- }
- /* update the negotiation status */
- if (result == CONFIG_REJ && option.type <= IPCP_OPTION_LIMIT)
- local_p->work.negotiate &= ~(1 << option.type); /*lint !e502 */
- }
- PPP_DEBUG_CHECKS ("IPCP NAK: valid");
- free_p (data);
- return 0;
- }
-
-
-
- /************************************************************************/
- /* Process configuration reject sent by remote host */
- static int
- ipcp_reject (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- struct ipcp_side_s *local_p = &(ipcp_p->local);
- int32 signed_length = config->len;
- struct option_hdr option;
- int last_option = 0;
-
- PPP_DEBUG_ROUTINES ("ipcp_reject()");
-
- /* ID field must match last request we sent */
- if (config->id != fsm_p->lastid) {
- PPP_DEBUG_CHECKS ("IPCP REJ: wrong ID");
- free_p (data);
- return -1;
- }
- /* Process in order, checking for errors */
- while (signed_length > 0 && ntohopt (&option, &data) != -1) {
- register int k;
-
- if ((signed_length -= option.len) < 0) {
- PPP_DEBUG_CHECKS ("IPCP REJ: bad header length");
- free_p (data);
- return -1;
- }
- if (option.type > IPCP_OPTION_LIMIT)
- PPP_DEBUG_CHECKS ("IPCP REJ: option out of range");
- else if (option.type < last_option || !(local_p->work.negotiate & (1 << option.type))) {
- PPP_DEBUG_CHECKS ("IPCP REJ: option out of order");
- free_p (data);
- return -1;
- }
- for (k = option.len - OPTION_HDR_LEN; k-- > 0;) {
- if (pullchar (&data) == -1) {
- PPP_DEBUG_CHECKS ("IPCP REJ: ran out of data");
- free_p (data);
- return -1;
- }
- }
- last_option = option.type;
-
- if (option.type <= IPCP_OPTION_LIMIT)
- local_p->work.negotiate &= ~(1 << option.type); /*lint !e502 */
- }
- PPP_DEBUG_CHECKS ("IPCP REJ: valid");
- free_p (data);
- return 0;
- }
-
-
-
- /************************************************************************/
- /* I N I T I A L I Z A T I O N */
- /************************************************************************/
-
- /* Reset configuration options before request */
- static void
- ipcp_reset (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- PPP_DEBUG_ROUTINES ("ipcp_reset()");
-
- ASSIGN (ipcp_p->local.work, ipcp_p->local.want);
- ipcp_p->local.work.other = ipcp_p->remote.want.address;
- ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
-
- ipcp_p->remote.work.negotiate = FALSE;
- ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
- }
-
-
-
- /************************************************************************/
- /* After termination */
- static void
- ipcp_stopping (struct fsm_s *fsm_p OPTIONAL)
- {
- PPP_DEBUG_ROUTINES ("ipcp_stopping()");
- }
-
-
-
- /************************************************************************/
- /* Close IPCP */
- static void
- ipcp_closing (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- /* free old slhc configuration, if any */
- slhc_free (ipcp_p->slhcp);
- ipcp_p->slhcp = NULL;
-
- #ifdef notdef
- if (PPPtrace > 1)
- trace_log (PPPiface, "%s PPP/IPCP Drop route to peer (%s)",
- ifp->name, inet_ntoa (ipcp_p->local.work.other));
-
- rt_drop (ipcp_p->local.work.other, (unsigned int) 32);
- #endif
- }
-
-
-
- /************************************************************************/
- /* configuration negotiation complete */
- static void
- ipcp_opening (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
- struct iface *ifp = fsm_p->ppp_p->iface;
- uint32 address = ipcp_p->local.work.address;
- int rslots = 0;
- int tslots = 0;
-
- /* Set our IP address to reflect negotiated option */
- if (address != ifp->addr) {
- /* address not the same as last time */
- if (Ip_addr == 0L)
- /* no global address */
- Ip_addr = address;
- else if (Ip_addr == ifp->addr)
- /* global was same as local; must be replaced */
- /* !!! TO DO: reset tcp connections */
- Ip_addr = address;
-
- ifp->addr = address;
-
- if (PPPtrace > 1)
- trace_log (PPPiface, "%s PPP/IPCP Setting new IP address: %s",
- ifp->name, inet_ntoa (address));
- }
- #ifdef notdef
- rt_add (ipcp_p->local.work.other, (unsigned int) 32, (int32) 0, ifp, (int32) 1, (int32) 0, (char) 1);
-
- if (PPPtrace > 1)
- trace_log (PPPiface, "%s PPP/IPCP Add route to peer (%s)",
- ifp->name, inet_ntoa (ipcp_p->local.work.other));
- #endif
-
- /* free old slhc configuration, if any */
- slhc_free (ipcp_p->slhcp);
- ipcp_p->slhcp = NULL;
-
- if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)
- rslots = ipcp_p->local.work.slots;
-
- if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS)
- tslots = ipcp_p->remote.work.slots;
-
- if (rslots != 0 || tslots != 0) {
- ipcp_p->slhcp = slhc_init (rslots, tslots);
-
- if (PPPtrace > 1)
- trace_log (PPPiface, "%s PPP/IPCP Compression enabled; Recv slots = %d, flag = %x;"
- " Xmit slots = %d, flag = %x", ifp->name, rslots,
- ipcp_p->local.work.slot_compress, tslots, ipcp_p->remote.work.slot_compress);
- }
- }
-
-
-
- /************************************************************************/
- /* Check the address against all other assigned addresses */
- static uint32
- ipcp_addr_idle (uint32 addr)
- {
- struct iface *ifp;
-
- /* Check if peer IP address is already in use on another interface */
- /* !!! need to look at *remote* address, not local! */
- for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
- if (ifp->addr == addr)
- return 0L;
- }
- return addr;
- }
-
-
-
- /************************************************************************/
- /* Assign the next unused address from a pool */
- static uint32
- ipcp_poolnext (struct ipcp_s *ipcp_p)
- {
- uint32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
- uint32 nextaddr = 0L;
-
- while (i-- > 0 && nextaddr == 0L) {
- if (++ipcp_p->local.want.other < ipcp_p->peer_min
- || ipcp_p->local.want.other > ipcp_p->peer_max)
- ipcp_p->local.want.other = ipcp_p->peer_min;
-
- nextaddr = ipcp_addr_idle (ipcp_p->local.want.other);
- }
- return (nextaddr);
- }
-
-
-
- /************************************************************************/
- /* Check if we have a specific IP address to assign to remote peer host */
- /* !!! TO DO: subnet mask, and routing */
- static uint32
- ipcp_lookuppeer (char *peerid)
- {
- char *buf;
- uint32 peer_addr = 0L;
-
- if (peerid == NULLCHAR)
- return 0L;
-
- if ((buf = userlookup (peerid, NULLCHARP, NULLCHARP, NULL, &peer_addr)) != NULLCHAR)
- free (buf);
-
- return (peer_addr);
- }
-
-
-
- /************************************************************************/
- /* Prepare to begin configuration exchange */
- static void
- ipcp_starting (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- PPP_DEBUG_ROUTINES ("ipcp_starting()");
-
- /* If not already set, and we know the name of the peer,
- * look in login file for an address
- */
- if (ipcp_p->remote.want.address == 0L)
- ipcp_p->remote.want.address = ipcp_lookuppeer (fsm_p->ppp_p->peername);
-
- /* If available, get next address from PPP pool */
- if ((ipcp_p->remote.want.address == 0L) && (ipcp_p->peer_min != 0L))
- ipcp_p->remote.want.address = ipcp_poolnext (ipcp_p);
-
- ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
- }
-
-
-
- /************************************************************************/
- static void
- ipcp_free (struct fsm_s *fsm_p)
- {
- struct ipcp_s *ipcp_p = fsm_p->pdv;
-
- slhc_free (ipcp_p->slhcp);
- }
-
-
-
- /* Initialize configuration structure */
- void
- ipcp_init (struct ppp_s *ppp_p)
- {
- struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
- struct ipcp_s *ipcp_p;
-
- PPPtrace = ppp_p->trace;
- PPPiface = ppp_p->iface;
-
- PPP_DEBUG_ROUTINES ("ipcp_init()");
-
- fsm_p->ppp_p = ppp_p;
- fsm_p->pdc = &ipcp_constants;
- fsm_p->pdv = ipcp_p = callocw (1, sizeof (struct ipcp_s));
-
- /* Set option parameters to first request defaults */
- ASSIGN (ipcp_p->local.want, ipcp_default);
- ipcp_p->local.will_negotiate = ipcp_negotiate;
-
- ASSIGN (ipcp_p->remote.want, ipcp_default);
- ASSIGN (ipcp_p->remote.work, ipcp_default);
- ipcp_p->remote.will_negotiate = ipcp_negotiate;
-
- fsm_init (fsm_p);
- }
-
-
- #endif /* PPP */
-